<template>
  <div class="fault-tolerant-image" :style="containerStyle">
    <!-- 加载状态 -->
    <div v-if="loading" class="image-loading">
      <div class="loading-spinner"></div>
    </div>
    
    <!-- 图片 -->
    <img
      v-if="src"
      ref="imageRef"
      :src="src"
      :alt="alt"
      :class="['image-content', { error: isError }]"
      :style="imageStyle"
      @load="handleLoad"
      @error="handleError"
    />
    
    <!-- 错误占位图 -->
    <div v-else-if="isError" class="image-error">
      <div class="error-icon">
        <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <circle cx="12" cy="12" r="10"></circle>
          <line x1="12" y1="8" x2="12" y2="12"></line>
          <line x1="12" y1="16" x2="12.01" y2="16"></line>
        </svg>
      </div>
      <div class="error-text">{{ errorText || '图片加载失败' }}</div>
    </div>
    
    <!-- 空状态 -->
    <div v-else class="image-empty">
      <div class="empty-icon">
        <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
          <rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
          <circle cx="8.5" cy="8.5" r="1.5"></circle>
          <polyline points="21 15 16 10 5 21"></polyline>
        </svg>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue'

// Props
const props = defineProps({
  // 图片源路径
  src: {
    type: String,
    default: ''
  },
  // 替代文本
  alt: {
    type: String,
    default: '图片'
  },
  // 宽度
  width: {
    type: [Number, String],
    default: 'auto'
  },
  // 高度
  height: {
    type: [Number, String],
    default: 'auto'
  },
  // 图片模式
  mode: {
    type: String,
    default: 'cover',
    validator: (value) => ['cover', 'contain', 'fill', 'none', 'scale-down'].includes(value)
  },
  // 错误占位文本
  errorText: {
    type: String,
    default: ''
  },
  // 是否显示加载状态
  showLoading: {
    type: Boolean,
    default: true
  }
})

// Refs
const imageRef = ref(null)

// State
const loading = ref(props.showLoading && props.src)
const isError = ref(false)
const fallbackSrc = ref('/assets/images/placeholder.png')

// 容器样式计算
const containerStyle = ref({
  width: typeof props.width === 'number' ? `${props.width}px` : props.width,
  height: typeof props.height === 'number' ? `${props.height}px` : props.height,
  position: 'relative',
  overflow: 'hidden',
  backgroundColor: '#f5f5f5'
})

// 图片样式计算
const imageStyle = ref({
  width: '100%',
  height: '100%',
  objectFit: props.mode,
  display: 'block'
})

// 处理图片加载成功
const handleLoad = () => {
  loading.value = false
  isError.value = false
}

// 处理图片加载失败
const handleError = () => {
  loading.value = false
  isError.value = true
}

// 监听src变化
watch(() => props.src, (newSrc) => {
  if (newSrc) {
    loading.value = props.showLoading
    isError.value = false
  } else {
    loading.value = false
    isError.value = false
  }
})

// 组件挂载时检查图片
onMounted(() => {
  if (!props.src) {
    loading.value = false
  }
})
</script>

<style scoped>
.fault-tolerant-image {
  display: inline-block;
  vertical-align: middle;
}

.image-content {
  transition: opacity 0.3s ease;
}

.image-content.error {
  opacity: 0;
  position: absolute;
  top: 0;
  left: 0;
}

.image-loading,
.image-error,
.image-empty {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #f5f5f5;
}

.loading-spinner {
  width: 30px;
  height: 30px;
  border: 3px solid #e0e0e0;
  border-top-color: #1890ff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.image-error {
  color: #999;
  font-size: 12px;
}

.error-icon,
.empty-icon {
  margin-bottom: 8px;
  color: #ccc;
}

.error-text {
  max-width: 90%;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
</style>